package lk.icta.core.dao.impl;

import lk.icta.common.AppConstants;
import lk.icta.common.ErrorCodes;
import lk.icta.common.dao.PreloadableDAO;
import lk.icta.common.dao.impl.BaseDAO;
import lk.icta.core.dao.LocalAuthorityDAO;
import lk.icta.core.entity.LocalAuthority;
import lk.icta.user.entity.User;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Query;
import java.util.*;


/**
 * @author Supun Nimesh Karunathilaka
 */
public class LocalAuthorityDAOImpl extends BaseDAO implements LocalAuthorityDAO, PreloadableDAO {

    private final Map<Integer, Map<Integer, String>> siNames = new HashMap<Integer, Map<Integer, String>>();
    private final Map<Integer, Map<Integer, String>> enNames = new HashMap<Integer, Map<Integer, String>>();
    private final Map<Integer, Map<Integer, String>> taNames = new HashMap<Integer, Map<Integer, String>>();


    @Transactional(propagation = Propagation.MANDATORY)
    public void addLocalAuthority(LocalAuthority localAuthority, User user) {
        logger.debug("Adding a LocalAuthority by {}", user.getUsername());
        localAuthority.setMode(LocalAuthority.Mode.ACTIVE);
        em.persist(localAuthority);
    }

    @Transactional(propagation = Propagation.MANDATORY)
    public void updateLocalAuthority(LocalAuthority localAuthority, User user) {
        logger.debug("LocalAuthority by {} by {}", localAuthority.getId(), user.getUsername());
        localAuthority.setMode(LocalAuthority.Mode.ACTIVE);
        em.merge(localAuthority);
    }

    @Transactional(propagation = Propagation.MANDATORY)
    public void inActiveLocalAuthority(LocalAuthority localAuthority, User user) {
        logger.debug("inActiveLocalAuthority by {} by {}", localAuthority.getId(), user.getUsername());
        localAuthority.setMode(LocalAuthority.Mode.INACTIVE);
        em.merge(localAuthority);
    }


    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LocalAuthority> getLocalAuthorityForDSDivisionByDSDivisionId(int divisionId, User user) {
        Query q = em.createNamedQuery("getLocalAuthorityForDSDivisionByDSDivisionId");
        q.setParameter("divisionId", divisionId);
        return q.getResultList();
    }

    public Map<Integer, String> getLocalAuthorityByDsDivisionId(int dsDivisionId, String language, User user) {
        Map<Integer, String> result = null;
        if (AppConstants.SINHALA.equals(language)) {
            result = getLocalAuthorityNamesImpl(siNames, dsDivisionId);
        } else if (AppConstants.ENGLISH.equals(language)) {
            result = getLocalAuthorityNamesImpl(enNames, dsDivisionId);
        } else if (AppConstants.TAMIL.equals(language)) {
            result = getLocalAuthorityNamesImpl(taNames, dsDivisionId);
        } else {
            handleException("Unsupported language : " + language, ErrorCodes.INVALID_LANGUAGE);
        }
        return result;
    }

    public LocalAuthority getLocalAuthorityById(int localAuthorityId, User user) {
        return em.find(LocalAuthority.class, localAuthorityId);
    }

    private Map<Integer, String> getLocalAuthorityNamesImpl(
            Map<Integer, Map<Integer, String>> namesByDistrict, int districtId) {

        Map<Integer, String> dsDivisionNames = namesByDistrict.get(districtId);
        if (dsDivisionNames != null) {
            return dsDivisionNames;
        }
        logger.warn("No Local Authority found for District : {}", districtId);
        return Collections.emptyMap();
    }

    /**
     * Loads all values from the database table into a cache
     */

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public void preload() {

        Query query = em.createQuery("SELECT loc FROM LocalAuthority loc WHERE loc.dsDivision.id=:divisionId");
        query.setParameter("divisionId", 3);
        List<LocalAuthority> results = query.getResultList();

        Map<Integer, String> subMap = null;

        for (LocalAuthority d : results) {
            updateCache(d);
        }

        logger.debug("Loaded : {} localAuthority from the database", results.size());

    }

    private void updateCache(LocalAuthority g) {
        Map<Integer, String> subMap;
        int id = g.getLocalAuthorityType().getId();
        //int divisionId = g.getCode();
        int divisionUKey = g.getId();

        //gnDivisionsByPK.put(g.getId(), g);

        subMap = siNames.get(id);
        if (subMap == null) {
            subMap = new TreeMap<Integer, String>();
            siNames.put(id, subMap);
        }
        subMap.put(divisionUKey, g.getSiName());

        subMap = enNames.get(id);
        if (subMap == null) {
            subMap = new TreeMap<Integer, String>();
            enNames.put(id, subMap);
        }
        subMap.put(divisionUKey, g.getEnName());

        subMap = taNames.get(id);
        if (subMap == null) {
            subMap = new TreeMap<Integer, String>();
            taNames.put(id, subMap);
        }
        subMap.put(divisionUKey, g.getTaName());
    }
}
